package com.sneakxy.mybase4j.generator;

import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;

import com.sneakxy.mybase4j.generator.config.GeneratorConfig;
import com.sneakxy.mybase4j.generator.core.Annotation;
import com.sneakxy.mybase4j.generator.core.Argument;
import com.sneakxy.mybase4j.generator.core.ClassDesigner;
import com.sneakxy.mybase4j.generator.core.ClassField;
import com.sneakxy.mybase4j.generator.core.ClassMethod;
import com.sneakxy.mybase4j.generator.core.ClassType;
import com.sneakxy.mybase4j.generator.utils.StringExtUtils;

/**
 * mybase4j代码生成器
 * @author 潜行的青衣
 * @see
 */
public class GeneratorMybase4jPlugin implements GeneratorPlugin {

	/* (non-Javadoc)
	 * @see com.sneakxy.mybase4j.generator.GeneratorPlugin#onBeforeBuilderCode(com.sneakxy.mybase4j.generator.GeneratorBuilder)
	 */
	@Override
	public void onBeforeBuilderCode(GeneratorBuilder builder, GeneratorConfig config) {
		ClassType idType = this.dealModel(builder, builder.getModelDesigner());
		this.dealRepository(builder, builder.getRepositoryDesigner(), idType);
		this.dealProviderInterface(builder, builder.getProviderInterfaceDesigner(), idType);
		this.dealProviderImpl(builder, builder.getProviderImplDesigner(), idType);
		this.dealServiceInterface(builder, builder.getServiceInterfaceDesigner(), idType);
		this.dealServiceImpl(builder, builder.getServiceImplDesigner(), idType);
	}
	
	private void dealServiceImpl(GeneratorBuilder builder, ClassDesigner service, ClassType idType) {
		service.setComment("/**\r\n * \r\n * @author 潜行的青衣\r\n * @see\r\n */");
		service.addAnnotation(new Annotation("org.springframework.stereotype.Service"));
		ClassType extType = new ClassType("com.sneakxy.mybase4j.base.service.BaseService");
		extType.addGenerics(builder.getModelName());
		extType.addGenerics(idType.getTypeName());
		extType.addGenerics(builder.getProviderInterfaceDesigner().getTypeName());
		service.setExtendsClass(extType);
		service.addOtherImport(builder.getModelDesigner());
		service.addOtherImport(idType);
		service.addOtherImport(builder.getProviderInterfaceDesigner());
		service.addImplementsClass(builder.getServiceInterfaceDesigner());
		
		ClassField provider = new ClassField(builder.getProviderInterfaceDesigner(), "provider");
		provider.setSetter(false);
		provider.setGetter(false);
		Annotation annotation = new Annotation("com.alibaba.dubbo.config.annotation.Reference");
		annotation.addArgument("version", "\"1.0.0\"");
		provider.addAnnotation(annotation);
		
		annotation = new Annotation("org.springframework.beans.factory.annotation.Autowired");
		annotation.addArgument("required", "false");
		provider.addAnnotation(annotation);
		
		annotation = new Annotation("org.springframework.beans.factory.annotation.Qualifier");
		annotation.addArgument("", "\"" +  StringExtUtils.lowerCaseFirstChar(builder.getProviderImplDesigner().getTypeName()) + "\"");
		provider.addAnnotation(annotation);
		service.addClassField(provider);
		
		ClassMethod method = new ClassMethod("getProvider");
		method.addAnnotation(new Annotation("java.lang.Override"));
		method.setReturnType(builder.getProviderInterfaceDesigner());
		method.addCodeLine("return this.provider;");
		service.addClassMethod(method);
	}
	
	private void dealServiceInterface(GeneratorBuilder builder, ClassDesigner service, ClassType idType) {
		service.setComment("/**\r\n * \r\n * @author 潜行的青衣\r\n * @see\r\n */");
		ClassType type = new ClassType("com.sneakxy.mybase4j.base.service.IBaseService");
		type.addGenerics(builder.getModelName());
		type.addGenerics(idType.getTypeName());
		service.setExtendsClass(type);
		service.addOtherImport(builder.getModelDesigner());
		service.addOtherImport(idType);
	}
	
	private void dealProviderImpl(GeneratorBuilder builder, ClassDesigner service, ClassType idType) {
		service.setComment("/**\r\n * \r\n * @author 潜行的青衣\r\n * @see\r\n */");
		Annotation annotation = service.addAnnotation(new Annotation("com.alibaba.dubbo.config.annotation.Service"));
		annotation.addArgument("version", "\"1.0.0\"");
		annotation.addArgument("interfaceClass", builder.getProviderInterfaceDesigner().getTypeName() + ".class");
		service.addAnnotation(new Annotation("org.springframework.stereotype.Service"));
		ClassType extType = new ClassType("com.sneakxy.mybase4j.base.provider.BaseProvider");
		extType.addGenerics(builder.getModelName());
		extType.addGenerics(idType.getTypeName());
		extType.addGenerics(builder.getRepositoryDesigner().getTypeName());
		service.setExtendsClass(extType);
		service.addOtherImport(builder.getModelDesigner());
		service.addOtherImport(idType);
		service.addOtherImport(builder.getRepositoryDesigner());
		service.addImplementsClass(builder.getProviderInterfaceDesigner());
		ClassMethod method = service.addConstructionMethod();
		method.addAnnotation(new Annotation("org.springframework.beans.factory.annotation.Autowired"));
		method.addArgument(new Argument(builder.getRepositoryDesigner(), "repository"));
		method.addCodeLine("super(repository);");
	}
	
	private void dealProviderInterface(GeneratorBuilder builder, ClassDesigner service, ClassType idType) {
		service.setComment("/**\r\n * \r\n * @author 潜行的青衣\r\n * @see\r\n */");
		ClassType type = new ClassType("com.sneakxy.mybase4j.base.provider.IBaseProvider");
		type.addGenerics(builder.getModelName());
		type.addGenerics(idType.getTypeName());
		service.setExtendsClass(type);
		service.addOtherImport(builder.getModelDesigner());
		service.addOtherImport(idType);
	}
	
	private void dealRepository(GeneratorBuilder builder, ClassDesigner repository, ClassType idType) {
		repository.setComment("/**\r\n * \r\n * @author 潜行的青衣\r\n * @see\r\n */");
		ClassType type = new ClassType("com.sneakxy.mybase4j.base.repository.BaseRepository");
		type.addGenerics(builder.getModelName());
		type.addGenerics(idType.getTypeName());
		repository.setExtendsClass(type);
		repository.addOtherImport(builder.getModelDesigner());
		repository.addOtherImport(idType);
		repository.addAnnotation(new Annotation("org.springframework.stereotype.Repository"));
	}
	
	private ClassType dealModel(GeneratorBuilder builder, ClassDesigner model) {
		model.setComment("/**\r\n * \r\n * @author 潜行的青衣\r\n * @see\r\n */");
		Annotation annotation = model.addAnnotation(new Annotation("com.sneakxy.mybatis.commons.annotations.Table"));
		annotation.addArgument("", "\"" + builder.getTableName() + "\"");
		
		List<ClassField> primaryKeys = builder.getPrimaryKeys();
		ClassField field = null;
		ClassType idType = null;
		//复合主键
		if(primaryKeys.size() > 1) {
			model.removeClassFields(primaryKeys);
			//主键类
			ClassDesigner modelKey = new ClassDesigner(new StringBuilder().append(model.toString(false)).append("Id").toString());
			modelKey.addImplementsClass(new ClassType(Serializable.class));
			modelKey.addClassField(primaryKeys);
			field = model.addClassField(0, new ClassField(modelKey, "id"));
			field.addAnnotation(new Annotation("org.springframework.data.annotation.Id"));
			idType = modelKey;
		} else {
			Iterator<ClassField> it = primaryKeys.iterator();
			field = null;
			while(it.hasNext()) {
				field = it.next();
				field.addAnnotation(new Annotation("org.springframework.data.annotation.Id"));
				idType = field.getType();
			}
		}
		this.addColumn(primaryKeys);
		this.addColumn(builder.getOtherFields());
		field = model.addClassField(0, new ClassField(new ClassType("long"), "serialVersionUID"));
		field.setValue("-1L");
		field.setFinalf(true);
		field.setStaticf(true);
		field.setSetter(false);
		field.setGetter(false);
		
		ClassType type = new ClassType("com.sneakxy.mybase4j.base.bean.BaseEntity");
		type.addGenerics(idType.getTypeName());
		model.setExtendsClass(type);
		
		Iterator<ClassField> it = model.getFields().iterator();
		String[] times = new String[]{"createtime", "updatetime"};
		int timesLength = 0;
		while(it.hasNext()) {
			field = it.next();
			if(ArrayUtils.contains(times, field.getName())) {
				timesLength ++;
			}
		}
		if(timesLength == times.length) {
			model.addImplementsClass(new ClassType("com.sneakxy.mybase4j.base.bean.TimeEntity"));
		}
		
		//生成主键类代码
		if(idType instanceof ClassDesigner) {
			try {
				ClassDesigner idTypeClass = ((ClassDesigner) idType);
				field = idTypeClass.addClassField(0, new ClassField(new ClassType("long"), "serialVersionUID"));
				field.setValue("-1L");
				field.setFinalf(true);
				field.setStaticf(true);
				field.setSetter(false);
				field.setGetter(false);
				idTypeClass.buildClass(builder.getDirs().getModelOutDir());
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return idType;
	}
	
	public void addColumn(List<ClassField> fields) {
		Iterator<ClassField> it = fields.iterator();
		ClassField field = null;
		Annotation annotation = null;
		while(it.hasNext()) {
			field = it.next();
			annotation = field.addAnnotation(new Annotation("com.sneakxy.mybatis.commons.annotations.Column"));
			annotation.addArgument("", "\"" + field.getExtra() + "\"");
		}
	}

	/* (non-Javadoc)
	 * @see com.sneakxy.mybase4j.generator.GeneratorPlugin#onAfterBuilderCode(com.sneakxy.mybase4j.generator.GeneratorBuilder)
	 */
	@Override
	public void onAfterBuilderCode(GeneratorBuilder builder, GeneratorConfig config) {
		
	}

}
